#pragma once

#include <folly/fibers/FiberManager.h>
#include <folly/io/async/AsyncSignalHandler.h>
#include <folly/io/async/EventBase.h>
#include <folly/logging/xlog.h>

#include <csignal>

namespace nexus {

class EventBaseStopSignalHandler : public folly::AsyncSignalHandler {
 public:
  explicit EventBaseStopSignalHandler(folly::EventBase* evb)
      : folly::AsyncSignalHandler(evb) {
    registerSignalHandler(SIGINT);
    registerSignalHandler(SIGQUIT);
    registerSignalHandler(SIGTERM);
  }

 protected:
  void
  signalReceived(int signal) noexcept {
    XLOG(INFO) << "Caught signal: " << signal << ". Stopping event-base...";
    folly::getEventBase()->terminateLoopSoon();
    XLOG(INFO) << "Event-base stopped";
  }
};

class EventBase {
 public:
  EventBase(/* args */);
  virtual ~EventBase();

  folly::EventBase*
  evb() {
    return &evb_;
  }

  /**
   * Add a task to fiber manager. All tasks will be awaited in `stop()`.
   */
  template <typename F>
  void
  addFiber(F&& func) {
    fiberTaskFutures_.emplace_back(
        fiberManager_.addTaskFuture(std::move(func)));
  }

  void run();
  void stop();

  void
  waitUntilRunning() {
    evb_.waitUntilRunning();
  }
  
  void
  waitUntilStopped() {
    std::this_thread::yield();
  }

 private:
  folly::EventBase evb_;
  folly::fibers::FiberManager& fiberManager_;
  std::vector<folly::Future<folly::Unit>> fiberTaskFutures_;
};

} // namespace nexus